package com.jtpay.sdk.jtpay;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.jtpay.sdk.activity.TokenParam;
import com.jtpay.sdk.jtpay.constant.PayConstant;
import com.jtpay.sdk.jtpay.constant.PayExceptionType;
import com.jtpay.sdk.jtpay.listener.PayUtilListener;
import com.jtpay.sdk.jtpay.model.PayChannelInfo;
import com.jtpay.sdk.jtpay.model.PayInfo;
import com.jtpay.sdk.jtpay.model.PayTypeModel;
import com.jtpay.sdk.jtpay.utils.PayExceptionUtil;
import com.jtpay.sdk.jtpay.utils.PayLogUtil;
import com.jtpay.sdk.util.JftConstants;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import static com.jtpay.sdk.util.JftConstants.JUN_FU_TONG_URL_STATUS;
import static com.jtpay.sdk.util.JftConstants.ORDER_PARAM;

public class PayUtil {
    private Activity mActivity;
    private HashMap<String, PayParam> mArrayMap = new HashMap<>();
    private HandlerThread mHandlerThread;
    private PayHandler mPayHandler;
    protected static TokenParam mTokenParam;
    private PayUtilListener mListener;
    private static final String TOKEN_ID = "token_id";
    private static final String APPID = "appid";
    private static final String PAY_JSON = "pay_json";
    private static final String PLUGIN = "android.intent.action.PAY_PLUGIN";
    private static final int GET_PAY_TYPE = 0X1;
    private static final int GET_PAY_PARAM = 0X1 << 1;
    private static final int DO_PAY = 0X1 << 2;
    private static final int SHOW_PAY_TYPE = 0X1 << 3;
    private static final int GET_CHANNEL = 0X1 << 4;
    private static final int SHOW_CHANNEL = 0X1 << 5;
    private PayInfo mPayInfo;
    private Toast mToast;
    private int mType;
    private List<PayChannelInfo> mPayChannelInfo = new ArrayList<>();
    private PayGetPayStatusListener mGetPayStatusListener;
    private GetPayPullUpListener mPayPullUpListener = null;

    public void setPayChannelInfo(List<PayChannelInfo> payChannelInfo) {
        mPayChannelInfo = payChannelInfo;
    }


    private Stack<PayUtilListener> mPayUtilListeners;

    //xingye weixin sdk
    private void weiXinSdkPayPlugin(String token, String appid) {
        PayLogUtil.log("weiXinSdkPayPlugin begin");
        Intent intent = new Intent(PLUGIN);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra(TOKEN_ID, token);
        intent.putExtra(APPID, appid);
        mActivity.startActivity(intent);
    }

    //nanyue weixin sdk
    private void weiXinPayJsonPlugin(String payJson) {
        PayLogUtil.log("weiXinPayJsonPlugin begin payJson = " + payJson);
        Intent intent = new Intent(PLUGIN);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra(PAY_JSON, payJson);
        mActivity.startActivity(intent);
        PayLogUtil.log("weiXinPayJsonPlugin end");
    }

    //xingye weixin sdk
//    private void weiXinSdkPay(String token, String appid) {
//        PayLogUtil.log("weiXinSdkPay token = " + token + " appid = " + appid);
//        RequestMsg msg = new RequestMsg();
//        msg.setTokenId(token);
//        msg.setTradeType(MainApplication.WX_APP_TYPE);
//        msg.setAppId(appid);
//        PayPlugin.unifiedAppPay(mActivity, msg);
//    }

    //nanyue weixin sdk
//    private void weiXinPayJson(String payJson) {
//        PayLogUtil.log("weiXinPayJson payJson = " + payJson);
//        if (!TextUtils.isEmpty(payJson)) {
//            try {
//                JSONObject jsonObject = new JSONObject(payJson);
//                String appId = jsonObject.getString("appid");
//                String nonceStr = jsonObject.getString("noncestr");
//                String prepayId = jsonObject.getString("prepayid");
//                String partnerId = jsonObject.getString("partnerid");
//                String packageValue = jsonObject.getString("package");
//                String sign = jsonObject.getString("sign");
//                String timeStamp = jsonObject.getString("timestamp");
//                IWXAPI wxapi = WXAPIFactory.createWXAPI(mActivity, appId);
//                wxapi.registerApp(appId);
//                PayReq payReq = new PayReq();
//                payReq.appId = appId;
//                payReq.nonceStr = nonceStr;
//                payReq.prepayId = prepayId;
//                payReq.partnerId = partnerId;
//                payReq.packageValue = packageValue;
//                payReq.sign = sign;
//                payReq.timeStamp = timeStamp;
//                wxapi.sendReq(payReq);
//            } catch (JSONException e) {
//                PayLogUtil.log("payNanYue wrong reason = " + e.getMessage());
//                e.printStackTrace();
//            }
//
//        }
//    }

    public void setActivity(Activity activity) {
        mActivity = activity;
        PayLogUtil.logBase("version code = " + PayConstant.VERSION_CODE);
        PayExceptionUtil.getInstance().init(activity.getApplicationContext());
        if (activity instanceof PayUtilListener) {
            PayUtilListener listener = (PayUtilListener) activity;
            mPayUtilListeners.push(listener);
        } else {
            throw new RuntimeException("Activity must implements PayUtilListener");
        }
    }


    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        PayPluginManager.getInstance(mActivity).onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    private void doPay() {

        if (mPayPullUpListener != null) {
            mPayPullUpListener.doPayPullup();
        }
        junPayDo();
    }

    private void junPayDo() {
        PayExcessiveActivity.startActivityForResult(mActivity, this, mPayInfo, mType);
    }

    private class PayHandler extends Handler {
        public PayHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            switch (what) {
                case GET_PAY_TYPE:
                    doGetPayType();
                    break;
                case GET_PAY_PARAM:
                    int typeId = msg.arg1;
                    doGetParams(typeId);
                    break;
                case DO_PAY:
                    doPay();
                    break;
                case SHOW_PAY_TYPE:
                    showPayTypeList();
                    break;
                case GET_CHANNEL:
                    doGetChannel();
                    break;
                case SHOW_CHANNEL:
                    showChannelList();
                    break;
                default:
                    break;
            }
        }
    }

    private void doGetChannel() {
        String payId = mPayInfo.getPaySystemId();
        String url = JftConstants.JUN_FU_TONG_URL_CHANNEL + payId + "?token=" + mPayInfo.getToken() + "&paytypeid=" + mPayInfo.getPayTypeId();
        PayLogUtil.log("doGetChannel onResponse url = " + url);
        OkHttpClient okHttpClient = new OkHttpClient();
        OkHttpClient client = okHttpClient.newBuilder().readTimeout(JftConstants.TIME_OUT, TimeUnit.SECONDS).connectTimeout(JftConstants.TIME_OUT, TimeUnit.SECONDS).build();
        client.newCall(new Request.Builder().url(url).build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                dismissDialog();
                PayLogUtil.log("doGetChannel onResponse");

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                dismissDialog();
                PayLogUtil.log("doGetChannel onResponse result = " + result);
                try {
                    JSONObject jsonObject = new JSONObject(result);
                    String flag = jsonObject.getString("flag");
                    if ("1".equals(flag)) {
                        JSONArray array = jsonObject.getJSONArray("msg");
                        int size = array.length();
                        List<PayChannelInfo> list = new ArrayList<>(size);
                        for (int i = 0; i < size; i++) {
                            JSONObject object = array.getJSONObject(i);
                            PayChannelInfo info = new PayChannelInfo();

                            String channel_id = object.getString("Channel_Id");
                            String chanel_name = object.getString("ChannelName");
                            if (chanel_name.contains("（苹果）") || chanel_name.toLowerCase().contains("ios")) {
                                continue;
                            }
                            String typeCode = object.getString("TypeCode");
                            String channelTypeCode = object.getString("ChannelTypeCode");
                            info.setChannelId(channel_id);
                            // add index for channel name
                            info.setChannelName(chanel_name);
                            info.setTypeCode(typeCode);
                            info.setChannelTypeCode(channelTypeCode);
                            list.add(info);
                        }
                        mPayInfo.setPayChannelInfo(list);
                        mPayHandler.sendEmptyMessage(SHOW_CHANNEL);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public PayUtil() {
        mHandlerThread = new HandlerThread(PayUtil.class.getSimpleName());
        mHandlerThread.start();
        mPayHandler = new PayHandler(mHandlerThread.getLooper());
        mPayInfo = new PayInfo();
        mArrayMap = new HashMap<>();
        mPayUtilListeners = new Stack<>();
    }

    private void doGetPayType() {
        String payId = mPayInfo.getPaySystemId();
        final String url = JftConstants.JUN_FU_TONG_URL_PAY_TYPE + payId + "?token=" + mPayInfo.getToken();
        PayLogUtil.log("doGetPayType url = " + url);
        OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(PayConstant.TIME_OUT, TimeUnit.SECONDS).readTimeout(PayConstant.TIME_OUT, TimeUnit.SECONDS).build();
        okHttpClient.newCall(new Request.Builder().url(url).build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                PayLogUtil.log("doGetPayType onFailure ");
                dismissDialog();
                showToast(PayExceptionType.GET_PAY_METHOD_FAILED.ordinal());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                PayLogUtil.log("doGetPayType onResponse result = " + result);
                try {
                    JSONObject jsonObject = new JSONObject(result);
                    if (jsonObject.getString("flag").equals("1")) {
                        ArrayList<PayTypeModel> payTypeModels = new ArrayList<>();
                        String info = jsonObject.getString("paytype");
                        PayLogUtil.log("doGetPayType decrypt info = " + info);
                        JSONArray jsonArray = new JSONArray(info);
                        for (int i = 0; i < jsonArray.length(); i++) {
                            PayTypeModel payTypeModel = new PayTypeModel();
                            JSONObject jsonObjectitem = jsonArray.getJSONObject(i);
                            String typeId = jsonObjectitem.getString("typeid");
                            payTypeModel.setTypeid(typeId);
                            payTypeModel.setTypename(jsonObjectitem.getString("typename"));
                            payTypeModel.setContactWay(jsonObjectitem.getString("remark"));
                            payTypeModels.add(payTypeModel);
                        }
                        mPayInfo.setPayTypeModels(payTypeModels);
                        mPayHandler.sendEmptyMessage(SHOW_PAY_TYPE);
                    } else {
                        PayLogUtil.log("doGetPayType flag exception");
                        showToast(PayExceptionType.RETURN_ERROR_DATA.ordinal());
                    }
                } catch (JSONException e) {
                    PayLogUtil.log("doGetPayType json exception");
                    showToast(PayExceptionType.SERVER_CONNECTION_EXCEPTION.ordinal());
                    e.printStackTrace();
                }
            }
        });
    }

    private void doGetParams(final int checked_id) {
        boolean secondPay = false;
        final String payId = mPayInfo.getPaySystemId();
        if (TextUtils.isEmpty(payId)) {
            dismissDialog();
            showToast(PayExceptionType.PAY_SYSTEM_ID_EMPTY.ordinal());
            return;
        }
        PayLogUtil.log("doGetParams checked_id = " + checked_id);
        String token = mPayInfo.getToken();
        String type = mPayInfo.getPayTypeId();
        final String channel_id = mPayChannelInfo.get(checked_id).getChannelId();
        String channelTypeCode = mPayChannelInfo.get(checked_id).getChannelTypeCode();
        String url = JftConstants.JUN_FU_TONG_URL_INFO + mPayInfo.getPaySystemId() + "?token=" + mPayInfo.getToken() + "&paytypeid=" + mPayInfo.getPayTypeId() + "&Channel_Id=" + channel_id + "&ChannelTypeCode=" + channelTypeCode;
        mPayInfo.resetPayParam();
        String key = token + type + channel_id;
        if (mArrayMap.containsKey(key)) {
            PayParam value = mArrayMap.get(key);
            mPayInfo.setImgUrl(value.getImgUrl());
            mPayInfo.setOpenUrl(value.getOpenUrl());
            mPayInfo.setAliUrl(value.getAliUrl());
            mPayInfo.setAliImgId(value.getAliImgId());
            mPayInfo.setPayToken(value.getPayToken());
            mPayInfo.setWXAppId(value.getWXAppId());
            mPayInfo.setSdkFlag(value.getSdkFlag());
            mPayInfo.setPayJson(value.getPayJson());
            mPayInfo.setPlugin(value.getPlugin());
            PayLogUtil.log("doGetParams hash value = " + value);
            secondPay = true;
        }
        PayLogUtil.log("doGetParams secondPay = " + secondPay);
        if (!secondPay) {
            OkHttpClient okHttpClient = new OkHttpClient();
            OkHttpClient client = okHttpClient.newBuilder().readTimeout(JftConstants.TIME_OUT, TimeUnit.SECONDS).connectTimeout(JftConstants.TIME_OUT, TimeUnit.SECONDS).build();

            client.newCall(new Request.Builder().url(url).build()).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    PayLogUtil.log("doGetParams onFailure ");
                    dismissDialog();
                    showToast(PayExceptionType.GET_PAY_METHOD_FAILED.ordinal());
                }

                @Override
                public void onResponse(Call call, okhttp3.Response response) throws IOException {
                    String result = response.body().string();
                    PayLogUtil.log("doGetParams onResponse result = " + result);
                    if (response.isSuccessful()) {
                        String info = "";
                        try {
                            JSONObject jsonObject = new JSONObject(result);
                            if (jsonObject.getString("flag").equals("1")) {
                                info = jsonObject.getString("msg");
                                JSONObject object = new JSONObject(info);
                                JSONArray jsonArray = object.optJSONArray("paramlist");
                                if (null == jsonArray) {
                                    String url = object.getString("url");
                                    PayLogUtil.log(" jsonArray url = " + url);
                                    mPayInfo.setImgUrl(url);
                                    String token = mPayInfo.getToken();
                                    String type = mPayInfo.getPayTypeId();
                                    PayParam payParam = new PayParam(mPayInfo.getAliImgId(), mPayInfo.getImgUrl(), mPayInfo.getOpenUrl(), mPayInfo.getWXAppId(), mPayInfo.getPayToken(), mPayInfo.getSdkFlag(), mPayInfo.getPayJson(), mPayInfo.getPlugin());
                                    mArrayMap.put(token + type + channel_id, payParam);
                                    pay();
                                } else {
                                    PayLogUtil.log(" jsonArray url = " + jsonArray.toString());
                                    for (int i = 0; i < jsonArray.length(); i++) {
                                        JSONObject jsonObjectItem = jsonArray.getJSONObject(i);
                                        String paramCode = jsonObjectItem.getString("paramcode");
                                        String paramvalue = jsonObjectItem.getString("paramvalue");
                                        switch (paramCode) {
                                            case "img":
                                                mPayInfo.setImgUrl(paramvalue);
                                                break;
                                            case "imgid":
                                                mPayInfo.setAliImgId(paramvalue);
                                                break;
                                            case "aliurl":
                                                mPayInfo.setAliUrl(paramvalue);
                                                break;
                                            case "isopen":
                                                mPayInfo.setOpenUrl(paramvalue);
                                                break;
                                            case "sdkflag":
                                                mPayInfo.setSdkFlag(paramvalue);
                                                break;
                                            case "payToken":
                                                mPayInfo.setPayToken(paramvalue);
                                                break;
                                            case "wxappid":
                                                mPayInfo.setWXAppId(paramvalue);
                                                break;
                                            case "json":
                                                mPayInfo.setPayJson(paramvalue);
                                                break;
                                            case "plugin":
                                                mPayInfo.setPlugin(paramvalue);
                                                break;
                                            default:
                                                break;
                                        }
                                    }
                                    String token = mPayInfo.getToken();
                                    String type = mPayInfo.getPayTypeId();
                                    PayParam payParam = new PayParam(mPayInfo.getAliImgId(), mPayInfo.getImgUrl(), mPayInfo.getOpenUrl(), mPayInfo.getWXAppId(), mPayInfo.getPayToken(), mPayInfo.getSdkFlag(), mPayInfo.getPayJson(), mPayInfo.getPlugin());
                                    mArrayMap.put(token + type + channel_id, payParam);
                                    pay();
                                }
                            } else {
                                dismissDialog();
                                showToast(PayExceptionType.RETURN_ERROR_DATA.ordinal());
                            }
                        } catch (JSONException e) {
                            dismissDialog();
                            showToast(info);
                            e.printStackTrace();
                        }
                    }
                }
            });
        } else {
            pay();
        }
    }

    public void setDoPAYListener(GetPayPullUpListener getPayPullUpListener) {
        this.mPayPullUpListener = getPayPullUpListener;
    }

    public void getPayStatus(PayGetPayStatusListener getPayStatusListener) {
        mGetPayStatusListener = getPayStatusListener;
        if (mPayInfo.getIsPaying()) {
            PayLogUtil.logFifth("doPayStatus start");
            if (TextUtils.isEmpty(mPayInfo.getToken())) {
                return;
            }
            String url = JUN_FU_TONG_URL_STATUS + ORDER_PARAM + "?token=" + mPayInfo.getToken();
            PayLogUtil.logBase("doPayStatus url = " + url);
            getStatus(url);
        }
    }

    private void getStatus(String url) {
        OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(
                PayConstant.TIME_OUT, TimeUnit.SECONDS).
                readTimeout(PayConstant.TIME_OUT, TimeUnit.SECONDS).build();
        okHttpClient.newCall(new Request.Builder().url(url).build()).enqueue(new okhttp3.Callback() {

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                PayLogUtil.log("PayUtil getPayStatus onResponse code = " + response.code());
                if (response.body() != null) {
                    String result = response.body().string();
                    PayLogUtil.log("PayUtil getPayStatus onResponse result = " + result);
                    if (response.isSuccessful()) {
                        try {
                            JSONObject jsonObject = new JSONObject(result);
                            if (jsonObject.getString("flag").equals("success")) {
                                String payStatus = jsonObject.getString("msg");
                                showStatus(Integer.parseInt(payStatus));
                                if (payStatus.equals("1")) {
                                    PayLogUtil.log("PayUtil getPayStatus onResponse success");
                                } else {
                                    PayLogUtil.log("PayUtil getPayStatus onResponse failure");
                                }
                            } else {
                                PayLogUtil.log("PayUtil getPayStatus onResponse failure response = " + jsonObject.toString());
                                showStatus(2);
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                            PayLogUtil.log("PayUtil getPayStatus onResponse failure with error = " + e.getMessage());
                            showToast(PayExceptionType.SERVER_CONNECTION_EXCEPTION.ordinal());
                            showStatus(2);

                        }
                    } else {
                        PayLogUtil.log("PayUtil getPayStatus onPayStatus failure");
                        showStatus(2);
                    }
                } else {
                    PayLogUtil.log("PayUtil getPayStatus onResponse response body = null");
                    showToast(PayExceptionType.RETURN_ERROR_DATA.ordinal());
                    showStatus(2);
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {
                PayLogUtil.log("PayUtil getPayStatus onFailure IOException = " + e.getMessage());
                showStatus(2);
            }
        });
    }

    void showStatus(final int payStatus) {
        if (null != mGetPayStatusListener) {
            mActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mGetPayStatusListener.onPayStatus(payStatus);
                }
            });
        }
    }


    private void showToast(int type) {
        checkListener();
        if (mListener != null) {
            mListener.onPayException(type, null);
        } else {
            showToast();
        }
    }

    private void showToast(String content) {
        checkListener();
        if (mListener != null) {
            mListener.onPayException(-1, content);
        } else {
            showToast();
        }
    }

    private void showPayTypeList() {
        checkListener();
        if (null != mListener) {
            mListener.onPayDataResult();
        } else {
            showToast();
        }
    }

    private void showChannelList() {
        checkListener();
        if (null != mListener) {
            mListener.onShowChannelList();
        } else {
            showToast();
        }
    }

    public void dismissDialog() {
        checkListener();
        if (mListener != null) {
            mListener.onPayProgressDialog();
        } else {
            showToast();
        }
    }

    private void pay() {
        mPayHandler.sendEmptyMessage(DO_PAY);
    }

    public void getPayParam(int typeId, int type) {
        mType = type;
        Message message = Message.obtain();
        message.what = GET_PAY_PARAM;
        message.arg1 = typeId;
        mPayHandler.sendMessage(message);

    }

    public PayInfo getPayInfo() {
        return mPayInfo;
    }

    public void getPayType() {
        mPayHandler.sendEmptyMessage(GET_PAY_TYPE);
    }

    public void getChannelList() {
        mPayHandler.sendEmptyMessage(GET_CHANNEL);
    }

    private void checkListener() {
        mListener = mPayUtilListeners.peek();
    }

    public void removeTopListener() {
        mPayUtilListeners.pop();
    }

    private void showToast() {
        if (null == mToast) {
            mToast = Toast.makeText(mActivity, "mListener is null ,please check", Toast.LENGTH_SHORT);
        }
        mToast.show();
    }

    private void startBrowser(String url) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        mActivity.startActivity(intent);
    }

    public interface PayGetPayStatusListener {
        void onPayStatus(int payStatus);
    }

    public interface GetPayPullUpListener {
        public void doPayPullup();
    }
}